#ifndef INTERPRETER_HPP_GUARD
#define INTERPRETER_HPP_GUARD

#include "kbase.hpp"
#include "analogy.hpp"
#include "literal.hpp"
#include "rule.hpp"

#include "boost_pch.hpp"

namespace mashine { namespace input {

/**
 * interpreter 
 */
class Interpreter
{
public:
	static Interpreter* instance();
	~Interpreter();	
	
	std::string & interprete(std::string const & input);
	
	void setBase(mashine::kb::KnowledgeBase * kBase);
	mashine::kb::KnowledgeBase * getBase();
	
	std::string getLastMessage();
	void setLastMessage(std::string & msg);


	/**
	 * this variable pointed on single instance of Interpreter class
	 */
	static Interpreter * inst;

protected:		
	/**
	 * grammar 
	 */
	struct Grammar : boost::spirit::qi::grammar<std::string::const_iterator, unsigned(), boost::spirit::ascii::space_type>
	{
	public:
		/**
		 * semantic std::string & name,
		 */
		struct Semantic
		{
			template <typename A, typename B = boost::fusion::unused_type, 
								  typename C = boost::fusion::unused_type, 
								  typename D = boost::fusion::unused_type>
			struct result { typedef void type; };
			
			/**
			 * Analogy build
			 */
			void operator()(mashine::kb::Analogy & analogy, std::string name, std::vector<std::string> & params) const;
			
			/**
			 * Literal or Fact build
			 */
			void operator()(mashine::kb::Literal & literal, std::string name, std::vector<std::string> & params) const;
			
			/**
			 * Word (upper or lower) build
			 */
			void operator()(std::string & word, std::vector<char> & chars) const;
			
			/**
			 * Rule build
			 */
			void operator()(mashine::kb::Rule & rule, mashine::kb::Literal notDenied, std::vector<mashine::kb::Literal> & params) const;
			
			/**
			 * Pair (upper or lower) build
			 */
			void operator()(std::vector<std::string> & pair, std::string name1, std::string name2) const;
			
			/**
			 * Goal build
			 */
			void operator()(std::vector<mashine::kb::Literal> & goal, std::vector<mashine::kb::Literal> & goal_) const;
			
			/**
			 * Inference goal 
			 */
			void operator()(std::vector<mashine::kb::Literal> const & goal) const;
			
			/**
			 * Add entity
			 */
			void operator()(mashine::kb::Literal & entity) const;
			void operator()(mashine::kb::Analogy & entity) const;
			void operator()(mashine::kb::Rule & entity) const;
			
			/**
			 * print kb
			 */
			void operator()(std::string command) const;
		};
	
		boost::spirit::qi::rule<std::string::const_iterator, unsigned(), boost::spirit::ascii::space_type> allRules;
		
		boost::spirit::qi::rule<std::string::const_iterator, mashine::kb::Literal(), boost::spirit::ascii::space_type> fact;
		
		boost::spirit::qi::rule<std::string::const_iterator, mashine::kb::Analogy(), boost::spirit::ascii::space_type> analogy;
				
		boost::spirit::qi::rule<std::string::const_iterator, mashine::kb::Rule(), boost::spirit::ascii::space_type> canon;
				
		boost::spirit::qi::rule<std::string::const_iterator, std::vector<mashine::kb::Literal>(), boost::spirit::ascii::space_type> goal;
		
		boost::spirit::qi::rule<std::string::const_iterator, std::string(), boost::spirit::ascii::space_type> command;
				
		/**
		 * use functor that create appropriate Entity-based object mashine::input::Interpreter::Grammar::
		 */
		boost::phoenix::function<Semantic> action;
				
		Grammar();
		
		virtual ~Grammar();
		
	protected:
		boost::spirit::qi::rule<std::string::const_iterator, std::string(), boost::spirit::ascii::space_type> lowerWord;
	
		boost::spirit::qi::rule<std::string::const_iterator, std::string(), boost::spirit::ascii::space_type> upperWord;
				
		boost::spirit::qi::rule<std::string::const_iterator, std::vector<std::string>(), boost::spirit::ascii::space_type> upperPair;
		
		boost::spirit::qi::rule<std::string::const_iterator, std::vector<std::string>(), boost::spirit::ascii::space_type> lowerPair;
	
		boost::spirit::qi::rule<std::string::const_iterator, mashine::kb::Literal(), boost::spirit::ascii::space_type> Literal;
	
	} gramm;
	
	/**
	 * pointer an logic engine instance to add knowlege to base
	 * and execute "logical inference"
	 */
	mashine::kb::KnowledgeBase * kBase;
	
	/**
	 * this message return to user by call method interprete
	 */
	std::string message;
	
	Interpreter();
};
	
}}

#endif